home *** CD-ROM | disk | FTP | other *** search
/ Space & Astronomy / Space and Astronomy (October 1993).iso / mac / VIEWERS / MSDOS / PIXIT.ARC / GIFDCD.C next >
Text File  |  1989-04-14  |  12KB  |  427 lines

  1.  
  2. #include <stdio.h>
  3. #include <io.h>
  4. #include <fcntl.h>
  5. #include <stdlib.h>
  6. #include <string.h>
  7.  
  8.  
  9. #define PSZ 768         /* Maximum palette size */
  10. #define BSZ 16384       /* Size of write buffer for delzw() */
  11.  
  12.  
  13. struct gifhead {
  14.   char s[6];
  15.   unsigned int w, h;
  16.   unsigned char c, b, z;
  17. };
  18.  
  19. struct image {
  20.   unsigned int l, t, w, h;
  21.   unsigned char m;
  22. };
  23.  
  24.  
  25. int _readc(int f)
  26. /* Read a character from file f, return -1 on end of file */
  27. {
  28.   unsigned char c;
  29.  
  30.   if (_read(f, &c, 1) == 1)
  31.     return c;
  32.   else
  33.     return -1;
  34. }
  35.  
  36.  
  37. long delzw(int g, int h, int n)
  38. /* Decompress a .GIF style LZW compressed data stream of n-bit symbols,
  39.    getting codes from file g and writing symbols (one per byte) to file
  40.    h.  delzw() returns the number of bytes written to file h.  n must be
  41.    in the range 2..8. */
  42. {
  43.   int   n2,             /* 2^n */
  44.         m,              /* Current code size in bits */
  45.         m2,             /* 2^m */
  46.         k,              /* Next available table entry */
  47.         c,              /* Code being expanded */
  48.         f,              /* Last symbol decoded */
  49.         i,              /* Code just read */
  50.         d,              /* Code read before this one */
  51.         j,              /* Number of bits left in *p */
  52.         a;              /* Bytes in next block */
  53.   unsigned char *p,     /* Pointer to current byte in read buffer */
  54.         *q,             /* Pointer past liast byte in read buffer */
  55.         b[255],         /* Read buffer */
  56.         *u,             /* Stack pointer into r */
  57.         r[4096],        /* Stack for code expansion */
  58.         s[4096];        /* Symbol entries in table */
  59.   int   t[4096];        /* Code entries in table */
  60.   unsigned char *w;     /* Write buffer pointer */
  61.   unsigned char y[BSZ];         /* Write buffer */
  62.   long e;               /* Count of bytes written */
  63.   static int z[] = {0,1,3,7,0xf,0x1f,0x3f,0x7f,0xff,0x1ff,0x3ff,
  64.                     0x7ff,0xfff,0x1fff,0x3fff,0x7fff};
  65.  
  66.  
  67.   /* Initialize buffers */
  68.   w = y;
  69.   e = 0;
  70.   p = q = b;
  71.   j = 8;
  72.  
  73.   /* Setup decompression parameters */
  74.   if (n < 2 || n > 8)
  75.     return -5;                  /* Bad symbol size */
  76.   n2 = 1 << n;
  77.   k = n2 + 2;
  78.   m2 = 1 << (m = n + 1);
  79.   f = d = -1;                   /* There is no old code yet */
  80.  
  81.   /* Do until termination code (2^n + 1) is read */
  82.   while (1)
  83.   {
  84.     /* Get next code: reads next m bits from file g, which is made of
  85.        blocks of 1..255 bytes, each preceded by a one byte count. */
  86.     if (j == 8)
  87.     {
  88.       if (++p >= q &&
  89.           (((a = _readc(g)) < 1) ||
  90.            (q = (p = b) + _read(g, b, a)) < b + a))
  91.         return -4;              /* Premature end of file */
  92.       j = 0;
  93.     }
  94.     c = *p;
  95.     if ((i = m + j) <= 8)
  96.     {
  97.       *p >>= m;
  98.       j = i;
  99.     }
  100.     else
  101.     {
  102.       if (++p >= q &&
  103.           (((a = _readc(g)) < 1) ||
  104.            (q = (p = b) + _read(g, b, a)) < b + a))
  105.         return -4;              /* Premature end of file */
  106.       c |= *p << (8 - j);
  107.       if (i <= 16)
  108.         *p >>= (j = i - 8);
  109.       else
  110.       {
  111.         if (++p >= q &&
  112.             (((a = _readc(g)) < 1) ||
  113.              (q = (p = b) + _read(g, b, a)) < b + a))
  114.           return -4;            /* Premature end of file */
  115.         c |= *p << (16 - j);
  116.         *p >>= (j = i - 16);
  117.       }
  118.     }
  119.     c &= z[m];
  120.     i = c;
  121.  
  122.     /* Check code */
  123.     if (c == n2 + 1)
  124.       break;                    /* Terminator symbol */
  125.     if (c > k)
  126.       return -3;                /* Bad code */
  127.  
  128.     /* See if clear code */
  129.     if (c == n2)
  130.     {
  131.       k = n2 + 2;
  132.       m2 = 1 << (m = n + 1);
  133.       f = d = -1;
  134.       continue;
  135.     }
  136.  
  137.     /* Empty stack */
  138.     u = r;
  139.  
  140.     /* Check for special case---if code is next code to be defined */
  141.     if (c == k)
  142.     {
  143.       if (d == -1)
  144.         return -2;              /* First code is not a symbol */
  145.       *u++ = f;
  146.       c = d;
  147.     }
  148.  
  149.     /* Build string backwards */
  150.     while (c >= n2)
  151.     {
  152.       *u++ = s[c];
  153.       c = t[c];
  154.     }
  155.  
  156.     /* Write string out forwards, update final character (f) */
  157.     f = c;
  158.     do {
  159.       *w++ = c;
  160.       if (w == y + BSZ)
  161.       {
  162.         _write(h, y, BSZ);
  163.         e += BSZ;
  164.         w = y;
  165.       }
  166.       if (u <= r)
  167.         break;
  168.       c = *--u;
  169.     } while (1);
  170.  
  171.     /* Put new entry in table, update code length, old code */
  172.     if (k < 4096 && d != -1)
  173.     {
  174.       t[k] = d;
  175.       s[k] = f;
  176.       if (++k >= m2 && m < 12)
  177.         m2 = 1 << ++m;
  178.     }
  179.     d = i;
  180.   }
  181.  
  182.   /* Check that termination code was in the last byte of data */
  183.   if (_readc(g) != 0)
  184.     return -1;                  /* File didn't end after terminator */
  185.  
  186.   /* Flush write buffer and return bytes written */
  187.   if (w - y)
  188.   {
  189.     _write(h, y, w - y);
  190.     e += w - y;
  191.   }
  192.   return e;
  193. }
  194.  
  195.  
  196. void gif(int f, int w, int e)
  197. /* Decode .gif file f: if e is 1, do an extended decode, of e is 2,
  198.    write a decompressed version of the .gif file to file w. */
  199. {
  200.   long n, t;
  201.   int b, c;
  202.   struct gifhead g;
  203.   struct image d;
  204.   unsigned char p[PSZ];
  205.  
  206.   /* Check GIF header */
  207.   if (_read(f, &g, sizeof(g)) != sizeof(g) ||
  208.            strncmp(g.s, "GIF87a", 6))
  209.     printf(" is not a GIF87a file.\n");
  210.   else
  211.   {
  212.     /* Show header information */
  213.     printf(" is %dx%dx%d bits and %d bits/color with ",
  214.            g.w, g.h, (g.c & 7) + 1, ((g.c >> 4) & 7) + 1);
  215.     if (g.c & 0x80)
  216.       printf("a ");
  217.     else
  218.       printf("no ");
  219.     printf("global color map\n");
  220.     if ((g.c & 8) || g.z)
  221.       printf("  !reserved bits were not all zero\n");
  222.  
  223.     /* If extended decode, read entire file */
  224.     if (e)
  225.     {
  226.       /* Show one more detail from header */
  227.       printf(" background color is %d\n", g.b);
  228.  
  229.       /* If /w, write crucial header information */
  230.       if (e == 2)
  231.       {
  232.         _write(w, "PX", 2);
  233.         _write(w, &(g.w), 6);
  234.       }
  235.  
  236.       /* Global color table is next */
  237.       if (g.c & 0x80)
  238.       {
  239.         c = 3 * (1 << ((g.c & 7) + 1));
  240.         if (e != 2)
  241.         {
  242.           if (lseek(f, c, SEEK_CUR) == -1L)
  243.           {
  244.             printf(" !file stopped in global color table\n");
  245.             return;
  246.           }
  247.         }
  248.         else                    /* Save global color table in p */
  249.         {
  250.           if (_read(f, p, c) != c)
  251.           {
  252.             printf(" !file stopped in global color table\n");
  253.             return;
  254.           }
  255.           for (b = 0; b < c; b++)
  256.             p[b] >>= 2;
  257.           for (; b < PSZ; b++)
  258.             p[b] = 0;
  259.         }
  260.       }
  261.       else
  262.         printf(" !no global color table---.pix file unusable\n");
  263.  
  264.       /* Read images and extension blocks */
  265.       while ((c = _readc(f)) == ',' || c == '!')
  266.  
  267.         /* Process image */
  268.         if (c == ',')
  269.         {
  270.           /* Initialize bits per pixel */
  271.           b = (g.c & 7) + 1;
  272.  
  273.           /* Read image descriptor */
  274.           if (_read(f, &d, sizeof(d)) != sizeof(d))
  275.           {
  276.             printf(" !file stopped in image descriptor\n");
  277.             return;
  278.           }
  279.           printf(" image: start %d/%d pixels from left/top,",
  280.                  d.l, d.t);
  281.           printf(" is %dx%d %s\n",
  282.                  d.w, d.h, d.m & 0x40 ? "interlaced" : "sequential");
  283.           if (d.m & 0x38)
  284.             printf("  !reserved bits were not all zero\n");
  285.           if (e == 2)
  286.           {
  287.             if (d.l || d.t || d.w != g.w || d.h != g.h || (d.m & 0x40))
  288.               printf("  !image not standard---.pix file unusable\n");
  289.             _write(w, &d, 8);
  290.             _write(w, p, PSZ);
  291.           }
  292.  
  293.           /* Local color map (if any) is next */
  294.           if (d.m & 0x80)
  295.           {
  296.             b = (d.m & 7) + 1;
  297.             printf("  local color map with %d bits/pixel\n", b);
  298.             if (lseek(f, 3 * (1L << b), SEEK_CUR) == -1L)
  299.             {
  300.               printf(" !file stopped in local color map\n");
  301.               return;
  302.             }
  303.             if (e == 2)
  304.               printf("  !has local color map---.pix file unusable\n");
  305.           }
  306.  
  307.           /* Get bits per symbol for compressed image */
  308.           if ((c = _readc(f)) == -1)
  309.           {
  310.             printf(" !file stopped in raster data\n");
  311.             return;
  312.           }
  313.           printf("  code size = %d bits\n", c);
  314.  
  315.           /* Go over image blocks if just /e */
  316.           if (e != 2)
  317.           {
  318.             n = t = 0;
  319.             while ((c = _readc(f)) != 0)
  320.             {
  321.               if (c == -1 || lseek(f, c, SEEK_CUR) == -1L)
  322.               {
  323.                 printf(" !file stopped in raster data block\n");
  324.                 return;
  325.               }
  326.               n++;
  327.               t += c;
  328.             }
  329.             printf("  compressed image = %ld bytes in %ld blocks\n",
  330.                    t, n);
  331.           }
  332.  
  333.           /* If /w, decompress image and write it out */
  334.           else
  335.             if ((t = delzw(f, w, c)) < 0)
  336.               printf("  !error %ld decompressing image\n", t);
  337.             else
  338.               printf("  decompressed image = %ld pixels\n", t);
  339.         }
  340.  
  341.         /* Process extension block */
  342.         else
  343.         {
  344.           if ((c = _readc(f)) == -1)
  345.           {
  346.             printf(" !file stopped in extension block\n");
  347.             return;
  348.           }
  349.           printf(" gif extension block with function code %d\n", c);
  350.           n = t = 0;
  351.           while ((c = _readc(f)) != 0)
  352.           {
  353.             if (c == -1 || lseek(f, c, SEEK_CUR) == -1L)
  354.             {
  355.               printf(" !file stopped in extension data block\n");
  356.               return;
  357.             }
  358.             n++;
  359.             t += c;
  360.           }
  361.           printf("  total extension data = %ld bytes in %ld blocks\n",
  362.                  t, n);
  363.         }
  364.  
  365.       /* Make sure images and extensions terminated with a semicolon */
  366.       if (c == ';')
  367.         printf(" file");
  368.       else
  369.         printf(" !file not");
  370.       printf(" properly terminated");
  371.  
  372.       /* See if hit end of file */
  373.       if (eof(f) != 1)
  374.         printf(" (but extra data at end)");
  375.  
  376.       /* Done reading file */
  377.       printf("\n\n");
  378.     }
  379.   }
  380.  
  381.   /* Close files */
  382.   _close(f);
  383.   if (e == 2)
  384.     _close(w);
  385. }
  386.  
  387.  
  388. void main(int argc, char *argv[])
  389. /* Process .gif files and options---only options allowed are /e for an
  390.    extended decode, and /w for a full decompression, writing the results
  391.    to the same filename, but with extension .pix. */
  392. {
  393.   int i, e, f, w;
  394.   char a[128];
  395.  
  396.   e = 0;                        /* Extended list off */
  397.   for (i = 1; i < argc; i++)
  398.     if (argv[i][0] == '/')
  399.       if ((argv[i][1] & 0x5f) == 'E')
  400.         e = 1;                  /* Extended list on */
  401.       else if ((argv[i][1] & 0x5f) == 'W')
  402.         e = 2;                  /* Write image data */
  403.       else
  404.         printf("(invalid option)\n");
  405.     else
  406.     {
  407.       printf(argv[i]);
  408.       strcat(strcpy(a, argv[i]), ".gif");
  409.       if ((f = _open(a, O_RDONLY)) == -1)
  410.         printf(".gif not found.\n");
  411.       else
  412.       {
  413.         if (e == 2)
  414.         {
  415.           strcat(strcpy(a, argv[i]), ".pix");
  416.           if ((w = _creat(a, 0)) == -1)
  417.           {
  418.             printf(".pix could not be created---downgrading to /e\n");
  419.             e = 1;
  420.             printf(argv[i]);
  421.           }
  422.         }
  423.         gif(f, w, e);
  424.       }
  425.     }
  426. }
  427.